package org.someone.settlement;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.someone.common.CustomMaths;
import org.someone.formular.Calculator;

import org.someone.common.SortByLengthComparator;

public class SettlementOp {
	
	public static final String TMP_PARA_MAP_KEY_REFACTORING = "refactoring";
	//private static 
	
	public static final String TMP_GROUP_MAP_KEY_ROWNUM = "rownum";
	public static final String TMP_GROUP_MAP_KEY_EVAL = "eval";
	public static final String TMP_GROUP_MAP_KEY_EVAL4INDEX = "evalindex";
	public static final String TMP_GROUP_MAP_KEY_EVAL4PRICE = "evalprice";
	public static final String TMP_GROUP_MAP_KEY_MODE = "mode";
	public static final String TMP_GROUP_MAP_KEY_Quantity = "quantity";
	public static final String TMP_GROUP_MAP_KEY_Weight = "weight";
	public static final String TMP_GROUP_MAP_KEY_Quality = "quality";
	public static final String TMP_GROUP_MAP_KEY_PRICETYPE = "pricetype";
	public static final String TMP_GROUP_MAP_KEY_EVAL4Quality = "evalquality";
	
	public static final String TMP_TERMS_MAP_KEY_GROUPNUM = "groupnum";
	public static final String TMP_TERMS_MAP_KEY_EVAL = "eval";
	public static final String TMP_TERMS_MAP_KEY_EVAL4INDEX = "evalindex";
	public static final String TMP_TERMS_MAP_KEY_FORMULA = "formula";
	public static final String TMP_TERMS_MAP_KEY_FORMULAPARA = "formulaparam";
	public static final String TMP_TERMS_MAP_KEY_PRICECODE = "pricecode";
//	public static final String TMP_TERMS_MAP_KEY_PRICETYPE = "pricetype";
	
	public static final String PRICE_MODE_WEIGHTING = "weighting";
	public static final String PRICE_MODE_BATCH = "batch";
	
	public static final String PRICE_MODE_KEY = "pricemode";
	
	public static final String SIGN_AND = " && "; 
	public static final String SIGN_EQUAL = " == "; 
	public static final String SIGN_UNEQUAL = " != "; 
	
	public static final String MAP_KEY_MONEY = "amountmoney";
//	public static final String MAP_KEY_PRICE = "price";
	
	public static final String DeductionPriceCode_Total = "增扣总价";
	public static final String DeductionPriceCode_Tonsofwater = "增扣数量";
	public static final String DeductionPriceCode_Adjustment = "指标调整";
	/**
	 * 提取符合条件要求的数据并重新构造一个List
	 * @param conditionEval		提取数据的条件
	 * @param sourcesList			源list
	 * @return					新的list
	 * @throws ScriptException	由于使用js处理表达式，所以需要抛出此异常
	 */
	public static List<Map<String,String>> extract(String conditionEval, List<Map<String,String>> sourcesList) throws ScriptException{
		List<Map<String,String>> resultList = new ArrayList<Map<String,String>>();
		List<String> keysList = getConditionKeys(conditionEval);
		for(int i=0; i < sourcesList.size(); i++){
			Map<String,String> sRowMap = sourcesList.get(i);
			if(judgeCondition(keysList, conditionEval, sRowMap)){
				resultList.add(sRowMap);
			}
		}
		return resultList;
	}

	/**
	 * 根据传入的值是否符合条件表达式
	 * @param keysList
	 * @param conditionEval	条件表达式	或者:|| ， 且 :&& ， 等于:== ， 大于:> ， 小于:< ， 大于等于:>= ， 小于等于:<= ， 不等于:!= 
	 * @param valMap
	 * @return
	 * @throws ScriptException
	 */
	public static boolean judgeCondition(List<String> keysList, String conditionEval, Map<String,String> valMap) throws ScriptException{
		if(conditionEval==null||"".equals(conditionEval)){
			return false;
		}
		ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); 
		for(int i=0; i< keysList.size(); i++){
			String strKey = keysList.get(i);
			engine.put(strKey.toUpperCase(), valMap.get(strKey));
		}
		//System.out.println(conditionEval);
		return Boolean.parseBoolean(String.valueOf(engine.eval(conditionEval.toUpperCase())));
	}
	
	/**
	 * 
	 * @param conditionEval	表达式
	 * @param val			值
	 * @return
	 * @throws ScriptException
	 */
	public static boolean judgeCondition(String conditionEval, Map<String,String> val) throws ScriptException{
		if(conditionEval==null||"".equals(conditionEval)){
			return false;
		}
		ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); 
		Iterator<Entry<String, String>> it = val.entrySet().iterator();
		while(it.hasNext()){
			Entry<String, String> e = (Entry<String, String>)it.next();
			engine.put(e.getKey(), val.get(e.getKey()));
		}
		return Boolean.parseBoolean(String.valueOf(engine.eval(conditionEval)));
	}
	
	/**
	 * 获得条件表达式中的变量
	 * @param conditionEval		条件表达式
	 * @return	变量的集合
	 */
	public static List<String> getConditionKeys(String conditionEval){
		List<String> excludeKeysList = new ArrayList<String>();	//公式的key
		for(int i=0 ; i<Calculator.funcArray.length; i++){
			excludeKeysList.add(Calculator.funcArray[i]);
		}
		List<String> resultList = new ArrayList<String>();
		if(conditionEval == null){
			return resultList;
		}
		String strKeyTmp = "";
		for(int i =0; i < conditionEval.length(); i++){
			char c = conditionEval.charAt(i);
			if(Character.isLetter(c)|| c=='_'){
				strKeyTmp += c;
				if(i+1 == conditionEval.length()){
					resultList.add(strKeyTmp);
				}
			}else{
				if(strKeyTmp.length()>0) {
					resultList.add(strKeyTmp);
					strKeyTmp = "";
				}
			}
		}
		resultList.removeAll(excludeKeysList);
		return new ArrayList<String>(new HashSet<String>(resultList)) ;
	}
	
	/**
	 * 加权平均方法
	 * @param weightkey		权重
	 * @param keys			需要加权的指标
	 * @param sources		数据源
	 * @return				加权后的结果
	 * @throws Exception 
	 */
	@Deprecated 
	public static Map<String,String> getWeightedMeans(String weightkey, List<String> keys, List<Map<String,String>> sources, Map<String,String> rounding) throws Exception{
		Map<String,Double> mapsum = new HashMap<String,Double>();
		Map<String,Double> mapweight = new HashMap<String,Double>();
		for(int i=0; i<sources.size(); i++){
			Map<String,String> mapsources = sources.get(i);
//			System.out.println(mapsources.get(weightkey));
			double weight = Double.parseDouble(mapsources.get(weightkey)==null?"0":mapsources.get(weightkey));
			for(int ki=0; ki< keys.size(); ki++){
				String key = keys.get(ki);
				double val = Double.parseDouble(mapsources.get(key)==null?"0":mapsources.get(key));
				double sumtmp = mapsum.get(key)==null?0:mapsum.get(key);
				sumtmp = sumtmp + weight*val;
				double weighttmp = mapweight.get(key)==null?0:mapweight.get(key);
				weighttmp = weighttmp + weight;
				mapsum.put(key, sumtmp);
				mapweight.put(key, weighttmp);
			}
		}
		Map<String,String> map = new HashMap<String,String>();
		for(int ki=0; ki< keys.size(); ki++){
			String key = keys.get(ki);
			double sumtmp = mapsum.get(key)==null?0:mapsum.get(key);
			double weighttmp = mapweight.get(key)==null?0:mapweight.get(key);
			if(weighttmp == 0){
				throw new Exception("加权过程中权重为0。");
			}
			int scale = Integer.parseInt(rounding.get(key)==null?"2":rounding.get(key));
			double value = CustomMaths.Round_new(CustomMaths.div(sumtmp, weighttmp), scale);
			map.put(key, String.valueOf(value));
		}
		return map;
	}
	

	/**
	 * 在数据sourcesList 中根据strWeightKey得到加权的strTargetkey默认根据数据中最大的小数位修约，如果数据中没有小数位则根据intRounding 修约
	 * @param strWeightKey
	 * @param strTargetkey
	 * @param sourcesList
	 * @param intRounding
	 * @return
	 */
	@Deprecated
	public static double getWeightedValue(String strWeightKey, String strTargetkey, List<Map<String,String>> sourcesList, int intRounding){
		double dbSumWeight = 0.0;
		double dbSumAmount = 0.0;
		double dbWeightTarget = 0.0;
		int intScale = -1;
		for(int i=0; i<sourcesList.size(); i++){
			Map<String,String> sRowMap = sourcesList.get(i);
			String strWeight = sRowMap.get(strWeightKey);
			double dbWeight = Double.parseDouble(strWeight==null?"0":strWeight);
			String strPrice = sRowMap.get(strTargetkey);
			double dbPrice = Double.parseDouble(strPrice==null?"0":strPrice);
			if(strPrice!=null && strPrice.indexOf(".")!=-1 && BigDecimal.valueOf(dbPrice).remainder(BigDecimal.valueOf(1)).doubleValue()>0){
				int intScaleTmp =  strPrice.length()-strPrice.indexOf(".")-1;
				intScale = intScaleTmp > intScale? intScaleTmp: intScale;
			}
			dbSumWeight = CustomMaths.add(dbSumWeight, dbWeight);
			dbSumAmount = CustomMaths.add(CustomMaths.mul(dbWeight, dbPrice),dbSumAmount);
		}
		if(dbSumWeight != 0.0)
			dbWeightTarget = CustomMaths.div(dbSumAmount, dbSumWeight, intScale==-1?intRounding:intScale);
		return dbWeightTarget;
	}
	
	/**
	 * 
	 * @param strWeightKey	加权权重
	 * @param strTargetkey	加权指标
	 * @param sourcesList	加权数据
	 * @param roundMode		修约方式
	 * @param intRounding	修约位数
	 * @return
	 */
	public static double getWeightedValue(String strWeightKey, String strTargetkey, List<Map<String,String>> sourcesList, String strRoundMode, int intRounding){
		return getWeightedValue(strWeightKey, strTargetkey, sourcesList, strRoundMode, intRounding, 0);
	}
	
	/**
	 * 
	 * @param strWeightKey	加权权重
	 * @param strTargetkey	加权指标
	 * @param sourcesList	加权数据
	 * @param roundMode		修约方式
	 * @param intRounding	修约位数
	 * @return
	 */
	public static double getWeightedValue(String strWeightKey, String strTargetkey, List<Map<String,String>> sourcesList, String strRoundMode, int intRounding, int deaultScale){
		double dbSumWeight = 0.0;
		double dbSumAmount = 0.0;
		double dbWeightTarget = 0.0;
		int intScale = -1;
		for(int i=0; i<sourcesList.size(); i++){
			Map<String,String> sRowMap = sourcesList.get(i);
			String strWeight = sRowMap.get(strWeightKey);
			double dbWeight = Double.parseDouble(strWeight==null?"0":strWeight);
			String strPrice = sRowMap.get(strTargetkey);
			double dbPrice = Double.parseDouble(strPrice==null?"0":strPrice);
			if(strPrice!=null && strPrice.indexOf(".")!=-1 && BigDecimal.valueOf(dbPrice).remainder(BigDecimal.valueOf(1)).doubleValue()!=0){
				int intScaleTmp =  strPrice.length()-strPrice.indexOf(".")-1;
				intScale = intScaleTmp > intScale? intScaleTmp: intScale;
			}
//			else{
//				intScale = 0 > intScale? 0: intScale;
//			}
			dbSumWeight = CustomMaths.add(dbSumWeight, dbWeight);
			dbSumAmount = CustomMaths.add(CustomMaths.mul(dbWeight, dbPrice),dbSumAmount);
		}
		if(intScale==-1 && intRounding==-1){
			intScale = deaultScale;
		}else if(intScale==-1){
			intScale = intRounding;
		}
		if(dbSumWeight != 0.0)
			dbWeightTarget = CustomMaths.div(dbSumAmount, dbSumWeight, intScale+10);
		if("round_new".equalsIgnoreCase(strRoundMode)){
			dbWeightTarget = CustomMaths.Round_new(dbWeightTarget, intScale);
		}else{
			dbWeightTarget = CustomMaths.round(dbWeightTarget, intScale);
		}
		return dbWeightTarget;
	}
	
	/**
	 * 在数据sourcesList中，得到strTargetKey 的和，默认根据数据中最大的小数位进行修约，如果数据中没有小数位则根据intRounding 修约
	 * @param strTargetKey
	 * @param sourcesList
	 * @param intRounding
	 * @return
	 */
	public static double getSumValue(String strTargetKey, List<Map<String,String>> sourcesList, int intRounding){
		double dbSumValue = 0.0;
		int intScale = -1;
		for(int i=0; i<sourcesList.size(); i++){
			Map<String,String> sRowMap = sourcesList.get(i);
			String strTargetValue = sRowMap.get(strTargetKey);
			double dbTargetValue = Double.parseDouble(strTargetValue==null?"0":strTargetValue);
			if(strTargetValue != null && strTargetValue.indexOf(".")!=-1 && BigDecimal.valueOf(dbTargetValue).remainder(BigDecimal.valueOf(1)).doubleValue()!=0){
				int intScaleTmp =  strTargetValue.length()-strTargetValue.indexOf(".")-1;
				intScale = intScaleTmp > intScale? intScaleTmp: intScale;
			}
			dbSumValue = CustomMaths.add(dbSumValue, dbTargetValue);
		}
		if(dbSumValue != 0.0)
			dbSumValue = CustomMaths.round(dbSumValue, intRounding==-1?intScale:intRounding);
		return dbSumValue;
	}
	
	/**
	 * 在数据sourcesList中，得到满足strEval条件的strTargetkey的值和，默认10位。
	 * @param strTargetkey
	 * @param strEval
	 * @param sourcesList
	 * @return
	 * @throws Exception
	 */
	public static double getSumValue(String strTargetkey, String strEval, List<Map<String,String>> sourcesList) throws Exception{
		List<Map<String,String>> tmpList = extract(strEval, sourcesList);
		return getSumValue(strTargetkey, tmpList, 10);
	}
	
	/**
	 * 替换strFormula中keyList所对应的值，值在valMap中
	 * @param strFormula
	 * @param keysList
	 * @param valMap
	 * @return
	 */
	public static String replaceFormula(String strFormula, List<String> keysList, Map<String,String> valMap){
		String strResult= strFormula;
		List<String> list = new ArrayList<String>();
		list.addAll(keysList);
		Collections.sort(list, new SortByLengthComparator());
		for(int i= list.size()-1; i>=0; i--){
			String strkey = list.get(i);
			String value = valMap.get(strkey);
			if(value != null && !"".equals(value))
				strResult = strResult.replaceAll(strkey, value);
		}
		return strResult;
	}
	
	/**
	 * 原替换公式被修改
	 * @param formula	公式
	 * @param val		变量库
	 * @return
	 */
	public static String replaceFormula(String formula, Map<String,String> val){
		return replaceFormula4Var(formula, val);
	}
	
	/**
	 * 将公式中的变量解析出来，根据map中的key进行替换，形成新的公式
	 * @param formula	公式
	 * @param val		变量库
	 * @return
	 */
	public static String replaceFormula4Var(String formula, Map<String,String> val){
		List<String> list = getConditionKeys(formula);
		return replaceFormula(formula, list, val);
	}
	
	/**
	 * 将公式中的变量解析出来，根据param中的变量替换，形成新的公式
	 * @param formula	公式
	 * @param param		参数表达式
	 * @return
	 */
	public static String replaceFormulaParam(String formula,String param){
		Map<String, String> val = new HashMap<String,String>();
		String[] params = param.split(",");
		for(int i=0; i< params.length; i++){
			String[] valarr = params[i].split("=");
			val.put(valarr[0], valarr[1]);
		}
		return replaceFormula4Var(formula, val);
	}
	
	public static boolean inArray(String array, String eval, boolean IgnoreCase){
		if(array==null || "".equals(array) || eval==null || "".equals(eval)){
			return false;
		}
		String arr = array.replaceAll("，", ",");
		String[] strarr = arr.split(",");
		for(int i =0; i< strarr.length; i++){
			if(IgnoreCase){
				if(strarr[i].equalsIgnoreCase(eval)) return true;
			}else{
				if(strarr[i].equals(eval)) return true;
			}
		}
		return false;
	}
	
	public static String UnitConvert(String key, String convertEval, String OrginalValue) throws Exception{
		String eval = convertEval.replaceAll(key, OrginalValue);
		return String.valueOf(Calculator.getCalculatorValue(eval));
	}
	
	public static String UnitConvertIgnoreCase(String key, String convertEval, String OrginalValue) throws Exception{
		return UnitConvert(key.toLowerCase(), convertEval.toLowerCase(), OrginalValue);		
		
	}
	
	/**
	 * @deprecated 该方法由CustomMaths中的同名方法替代
	 * @param str
	 * @return
	 */
	public static boolean isNumeric(String str){ 
	   Pattern pattern = Pattern.compile("[0-9]*"); 
	   Matcher isNum = pattern.matcher(str);
	   if( !isNum.matches() ){
	       return false; 
	   } 
	   return true; 
	}
	

	public static Map<String,String> getGroupMap4Rownum(List<Map<String,String>> group, String rownum){
		if(rownum==null || "".equals(rownum)){
			return null;
		}
		Map<String,String> rowmap = new HashMap<String,String>();
		for(int i=0; i< group.size(); i++){
			Map<String,String> row = group.get(i);
			if(rownum.equals(row.get(TMP_GROUP_MAP_KEY_ROWNUM))){
				rowmap = row;
			}
		}
		return rowmap;
	}
	public static final String PRICE_MODE_SUM = "sum";
	

	
	
	public static Map<String,String> getSumValues(List<String> keys, List<Map<String,String>> sources, Map<String,String> rounding) throws Exception{
		Map<String,String> map = new HashMap<String,String>();
		for(int i=0; i< keys.size(); i++){
			String key = keys.get(i);
			int scale = Integer.parseInt(rounding.get(key)==null?"2":rounding.get(key));
			double value = getSumValue(key, sources, scale);
			map.put(key, String.valueOf(value));
		}
		return map;
	}
	
}
